package org.jeecg.activiti.controller;

import java.text.ParseException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

import org.activiti.engine.HistoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.activiti.entity.ActReModelFormData;
import org.jeecg.activiti.entity.ActivitiConstant;
import org.jeecg.activiti.entity.ActivitiTaskVo;
import org.jeecg.activiti.service.IActKNodeDesignService;
import org.jeecg.activiti.service.IActReModelFormDataService;
import org.jeecg.activiti.service.IActivitiTaskService;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.online.cgform.service.IOnlCgformFieldService;
import org.jeecg.modules.online.cgform.util.SqlSymbolUtil;
import org.jeecg.modules.online.config.exception.ActScriptException;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.api.client.util.ArrayMap;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

/**
 * 流程任务管理
 */
@RestController
@RequestMapping("/activiti/task")
@Api(tags = "流程任务管理")
public class ActivitiTaskController {

    @Autowired
    private TaskService taskService;
    
    @Autowired
    private HistoryService historyService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private IActReModelFormDataService iActReModelFormDataService;

    @Autowired
    private IActivitiTaskService iActivitiTaskService;
    
    @Autowired
    private ISysUserService sysUserService;
    
    @Autowired
    private IOnlCgformFieldService fieldService;

    @Autowired
    private IActKNodeDesignService actKNodeDesignService;
    
    /**
     * 拾取任务
     * @param taskId
     * @return
     */
    @GetMapping("/claimTask")
    @ApiOperation(value = "拾取任务", notes = "拾取任务")
    public Result<Object> claimTask(@ApiParam("任务id") @RequestParam String taskId){
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        //校验该用户有没有拾取任务的资格
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task != null) {
			if (task.getAssignee() != null) {
				return Result.error("该任务已被其他同事拾取。");
			} else {
				taskService.claim(taskId, sysUser.getUsername());
				}
		} else {
            return Result.error("没有权限拾取该任务。");
        }
        return Result.OK();
    }
    
    /**
     * 审批通过
     * @return
     *
     */
    @PostMapping("/completeTask")
    @ApiOperation(value = "任务节点审批通过", notes = "任务节点审批通过")
    @Transactional
    public Result<Object> completeTask(@RequestBody Map<String, Object> params) throws ActScriptException {
        //任务id
        String taskId = org.jeecg.activiti.util.StringUtils.objToString(params.get("taskId"));
        //流程实例id
        String procInstId = org.jeecg.activiti.util.StringUtils.objToString(params.get("procInstId"));
        //表单数据id
        String formDataId = org.jeecg.activiti.util.StringUtils.objToString(params.get("formDataId"));
        //抄送人username（多个用英文逗号隔开）
        String usernames = org.jeecg.activiti.util.StringUtils.objToString(params.get("usernames"));
        //意见评论
        String comment = org.jeecg.activiti.util.StringUtils.objToString(params.get("comment"));
        //审批类型(0:同意、1:不同意、2:驳回)
        int flag = params.get("flag") != null ? Integer.parseInt(params.get("flag").toString()) : 0;
        //附加表单数据Id
        String appendFormDataId = org.jeecg.activiti.util.StringUtils.objToString(params.get("appendFormDataId"));
        //附加表单Id
        String appendFormId = org.jeecg.activiti.util.StringUtils.objToString(params.get("appendFormId"));
        //流程模型Id
        String modelId = org.jeecg.activiti.util.StringUtils.objToString(params.get("modelId"));
        //附加表单数据
        String formData = org.jeecg.activiti.util.StringUtils.objToString(params.get("formData"));
        //驳回目标任务节点ID
        String nodeId = org.jeecg.activiti.util.StringUtils.objToString(params.get("nodeId"));
        //上传的附件
        String files = org.jeecg.activiti.util.StringUtils.objToString(params.get("files"));
        
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();

        // 处理流程表单数据
        ActReModelFormData actReModelFormData = iActReModelFormDataService.getById(formDataId);
        Map<String, Object> variables;
        if(actReModelFormData.getTableName() !=null && !"".equals(actReModelFormData.getTableName())){
        	variables = this.fieldService.queryBpmData(actReModelFormData.getTableId(), actReModelFormData.getTableName(), actReModelFormData.getDataId());
        	variables = SqlSymbolUtil.getValueType(variables);
        }else{
        	variables = JSONObject.toJavaObject(JSONObject.parseObject(actReModelFormData.getFormData()), Map.class);
        }
        
        String tableName = actReModelFormData.getTableName();
        String recordId = "";
        if(!"".equals(tableName) && tableName != null){
            recordId = variables.get("id")+"";
            variables.put("bpm$tableName", tableName);
            variables.put("bpm$tableId", actReModelFormData.getTableId());
        }
        
        // 查询流程任务
        Task myTask = taskService.createTaskQuery().taskId(taskId).singleResult();
		if(myTask == null) {
        	return Result.error("该任务已办理");
        }
		
		String userId = historyService.createHistoricProcessInstanceQuery().processInstanceId(myTask.getProcessInstanceId()).singleResult().getStartUserId();
		SysUser user = sysUserService.getUserByName(userId);
		if(user != null){
			variables.put("bpm$user", user);
		}
        // 处理附加表单数据
        if (!StringUtils.isEmpty(formData)) {
            Map<String, Object> tempMap = JSONObject.toJavaObject(JSONObject.parseObject(formData), Map.class);
            if(MapUtils.isNotEmpty(tempMap)) {
            	Iterator<Entry<String, Object>> iterator = tempMap.entrySet().iterator();
            	while(iterator.hasNext()) {
            		Entry<String, Object> entry = iterator.next();
            		if(entry.getValue() != null) {
            			try {
            				String date = entry.getValue().toString();
							DateUtils.parseDate(date, "yyyy-MM-dd");
							tempMap.put(entry.getKey(), date + "T23:59:59");
						} catch (ParseException e) {
							
						}
            		}
            	}
            }
            variables.putAll(tempMap);
        }

        variables.put("flag", flag);

        Map<String, Object> transientVariables = taskService.getVariables(taskId);
        transientVariables.put("flag", flag);

        
        // 处理意见
        iActivitiTaskService.handleResult(taskId, procInstId, flag, comment, myTask.getTaskDefinitionKey(), sysUser.getUsername(), myTask.getExecutionId());

        // 保存附加表单数据
        iActivitiTaskService.saveActKAppendFormData(taskId, sysUser.getUsername(), formData, appendFormId, procInstId, modelId, myTask.getTaskDefinitionKey(), appendFormDataId, myTask.getExecutionId());

        // 保存上传的附件
        iActivitiTaskService.saveFiles(myTask, procInstId, files, sysUser.getUsername());

        // 处理抄送人
        iActivitiTaskService.handelDuplicate(usernames, procInstId, modelId, myTask, sysUser);
        

        if (flag != 2) {
            iActivitiTaskService.handleCompleteTask(taskId, procInstId, comment, variables, transientVariables, myTask, actReModelFormData);

            // 更新流程状态
            boolean b = iActivitiTaskService.handleProcessStatus(procInstId, formDataId, flag);
    		if(b && tableName != null && !"".equals(tableName)){
            	this.fieldService.editFormBpmStatus(recordId, tableName, (flag == 1?ActivitiConstant.HANDLE_STATUS_WTG:ActivitiConstant.HANDLE_STATUS_YWC)+"");
            }
            
        } else if (flag == 2 && StringUtils.isEmpty(nodeId)){
            iActivitiTaskService.handleCompleteTask(taskId, procInstId, comment, variables, transientVariables, myTask, actReModelFormData);

            // 更新流程状态
            boolean b = iActivitiTaskService.handleProcessStatus(procInstId, formDataId, flag);
            if(b && tableName != null && !"".equals(tableName)){
            	this.fieldService.editFormBpmStatus(recordId, tableName, ActivitiConstant.HANDLE_STATUS_YWC+"");
            }
        } else if (flag == 2 && !StringUtils.isEmpty(nodeId)){
        	taskService.addComment(taskId, procInstId, comment == null ? "" : comment);
            iActivitiTaskService.rejectTargetNode(taskId, nodeId, comment == null ? "" : comment, variables, transientVariables, sysUser, tableName);
        }

        // todo  解析节点表达式
        actKNodeDesignService.postProcessFormdataByScript(actReModelFormData.getModelId(),myTask.getTaskDefinitionKey(),variables);

        return Result.OK();
    }



    /**
     * 审批不通过
     * @return
     */
    @ApiOperation(value="流程-任务节点审批 驳回至发起人", notes="任务节点审批 驳回至发起人")
    @GetMapping(value = "/back")
    public Result<Object> back(@ApiParam("任务id") @RequestParam String id,
                               @ApiParam("流程实例id") @RequestParam String procInstId,
                               @ApiParam("表单数据id") @RequestParam String formDataId,
                               @ApiParam("意见评论") @RequestParam(required = false) String comment) {
        taskService.addComment(id, procInstId, comment);
        // 删除流程实例
        runtimeService.deleteProcessInstance(procInstId, "backed");
        ActReModelFormData actReModelFormData = iActReModelFormDataService.getOne(new QueryWrapper<ActReModelFormData>().eq("id", formDataId));
        if(actReModelFormData.getTableName()!=null && !"".equals(actReModelFormData.getTableName())){
        	 JSONObject json = JSONObject.parseObject(actReModelFormData.getFormData());
             this.fieldService.editFormBpmStatus(json.getString("id"), actReModelFormData.getTableName(), ActivitiConstant.HANDLE_STATUS_YTH+"");
        }
        // 修改用户提交流程状态为已退回
        iActReModelFormDataService.update(new UpdateWrapper<ActReModelFormData>().set("status", ActivitiConstant.RESULT_FAIL).set("process_instance_id", "").eq("id", formDataId));
        
        return Result.OK();
   }
    
    @GetMapping("/urging")
    @ApiOperation(value = "催办流程实例", notes = "催办流程实例")
    public Result<Object> urging(@ApiParam("流程实例id") @RequestParam String procInstId){
    	iActivitiTaskService.urging(procInstId);
    	return Result.OK();
    }

    /**
     * 查询我的任务列表
     * @return
     */
    @GetMapping("/getMyTaskList")
    @ApiOperation(value="查询待办任务列表", notes="查询待办任务列表")
    @ResponseBody
    public Result<Object> getMyTaskList(String modelName, String modelKey, String creator, @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
                                @RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
        Map<String, Object> result = iActivitiTaskService.getMyTaskList(modelName, modelKey, creator, pageNo, pageSize);
        return Result.OK(result);
    }
    
    /**
     * 查询我的所有任务
     * @return
     */
    @AutoLog(value = "我的任务-我的所有任务分页查询")
	@ApiOperation(value="我的任务-我的所有任务分页查询", notes="我的任务-我的所有任务分页查询")
	@GetMapping(value = "/getMyAllTaskList")
	public Result<?> getMyAllTaskList(ActivitiTaskVo activitiTaskVo,
								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
								   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
								   HttpServletRequest req) {
    	Page<ActivitiTaskVo> page = new Page<ActivitiTaskVo>(pageNo, pageSize);
    	
    	if(activitiTaskVo != null && !StringUtils.isEmpty(activitiTaskVo.getCreator())) {
    		String[] creatorArr = activitiTaskVo.getCreator().split(",");
    		if(creatorArr != null && creatorArr.length > 0) {
    			List<String> taskInitiatorList = Arrays.asList(creatorArr);
    			activitiTaskVo.setTaskInitiatorList(taskInitiatorList);
    		}
    	}
    	
    	LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
    	List<String> roleList = this.sysUserService.getRole(sysUser.getUsername());
    	activitiTaskVo.setRoleList(roleList);
    	activitiTaskVo.setAssignee(sysUser.getUsername());
    	IPage<ActivitiTaskVo> activitiTaskVoList = this.iActivitiTaskService.getMyTaskList(page, activitiTaskVo);
		return Result.OK(activitiTaskVoList);
	}

    /**
     * 委托任务
     * @param taskId
     * @param userId
     * @return
     */
    @GetMapping("/entrustTask")
    @ApiOperation(value = "委托个人任务", notes = "委托个人任务")
    public Result<Object> entrustTask(@ApiParam(value = "taskId", name="任务id") String taskId,
                              @ApiParam(value = "userId", name="委托人id")  String userId) {
        taskService.setAssignee(taskId, userId);
        return Result.OK();
    }

    /**
     * 获取下一个用户任务节点
     * @param taskId
     * @return
     */
    @GetMapping("/getNextTaskInfo")
    @ApiOperation(value = "获取下一个用户任务节点", notes = "获取下一个用户任务节点")
    public Result<Object> getNextTaskInfo(@ApiParam(value = "taskId", name="任务id")  String taskId) {
        try {
            Map<String, Object> nextNodeMap = iActivitiTaskService.getNextTaskInfo(taskId);
            return Result.OK(nextNodeMap);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("系统异常，请联系管理员。");
        }
    }

    @GetMapping("/getMyCreateTask")
    @ApiOperation(value = "查询我发起的流程", notes = "查询我发起的流程")
    public Result<Object> getMyCreateTask(@ApiParam(value = "processInstanceId", name="实例id") String processInstanceId,
    		@ApiParam(value = "active", name="是否活动") String active) {

        List<Map<String,Object>> resultList = iActivitiTaskService.getMyCreateTask(processInstanceId,active);

        Map<String, Object> result = new ArrayMap<>();
        result.put("records", resultList);
        result.put("total", resultList.size());

        return Result.OK(result);
    }
    
    @GetMapping("/getAllTask")
    @ApiOperation(value = "查询所有流程", notes = "查询所有流程")
    public Result<Object> getAllTask(@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
			   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
			   @RequestParam(name="creator", required = false) String creator,
			   @RequestParam(name="modelKey", required = false) String modelKey,
			   @RequestParam(name="modelName", required = false) String modelName) {
    	Page<Map<String,Object>> page = new Page<Map<String,Object>>(pageNo, pageSize);
    	IPage<Map<String,Object>> result = iActivitiTaskService.getAllTaskWithPage(creator,modelName,modelKey,page);
    	/*List<Map<String,Object>> resultList = iActivitiTaskService.getAllTask();

        Map<String, Object> result = new ArrayMap<>();
        result.put("records", resultList);
        result.put("total", resultList.size());*/

        return Result.OK(result);
    }
    
    @GetMapping("/getApprovalRecord")
    @ApiOperation(value = "查询流程进度", notes = "查询流程进度")
    public Result<Object> getApprovalRecord(@ApiParam(value = "tableId", name="Onl表ID") String tableId,
    		@ApiParam(value = "dataId", name="数据ID") String dataId) {

        List<Map<String,Object>> resultList = iActivitiTaskService.getApprovalRecord(tableId, dataId);

        Map<String, Object> result = new ArrayMap<>();
        result.put("records", resultList);
        result.put("total", resultList.size());

        return Result.OK(result);
    }

    @GetMapping("/suspendProcess")
    @ApiOperation(value = "挂起流程实例", notes = "挂起流程实例")
    public Result<Object> suspendProcess(@ApiParam(value = "流程实例Id", name="流程实例id") String processInstanceId) {
        runtimeService.suspendProcessInstanceById(processInstanceId);
        return Result.OK();
    }

    @GetMapping("/activateProcess")
    @ApiOperation(value = "激活流程实例", notes = "激活流程实例")
    public Result activateProcess(@ApiParam(value = "流程实例Id", name="流程实例id") String processInstanceId) {
        runtimeService.activateProcessInstanceById(processInstanceId);
        return Result.OK();
    }

    @GetMapping("/getGroupTaskList")
    @ApiOperation(value = "查询组任务列表", notes = "查询组任务列表")
    public Result<Object> getGroupTaskList(String modelKey, String modelName){
        List<Map<String,Object>> resultList = iActivitiTaskService.getGroupTaskList(modelKey, modelName);

        Map<String, Object> result = new HashMap<>();
        result.put("total", resultList.size());
        result.put("records", resultList);

        return Result.OK(result);
    }

    /**
     * 退回到上一个节点
     * @param taskId
     */
    @GetMapping("/backProcess")
    @ApiOperation(value = "退回到上个任务节点", notes = "退回到上个任务节点")
    public void backProcess(@ApiParam(value = "taskId", name="当前任务ID") String taskId) {

        iActivitiTaskService.backProcess(taskId);
    }

    /**
     * 退回到任意节点
     * @param taskId
     * @param nodeId
     * @return
     */
    @GetMapping("/rejectTargetNode")
    @ApiOperation(value = "退回到任意任务节点", notes = "退回到任意任务节点")
    public Result<Object> rejectTargetNode(@ApiParam(value = "taskId", name = "当前任务ID") @RequestParam(value = "taskId") String taskId,
                                   @ApiParam(value = "nodeId", name = "目标节点ID") @RequestParam(value = "nodeId") String nodeId,
                                           @ApiParam(value = "record", name = "驳回理由") @RequestParam(value = "record") String record) {
        Map<String, Object> variables = new HashMap<>();
        Map<String, Object> transientVariables = new HashMap<>();
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        return iActivitiTaskService.rejectTargetNode(taskId, nodeId, record, variables, transientVariables,sysUser,null);
    }

    @GetMapping("/cancellation")
    @ApiOperation(value = "作废流程实例", notes = "作废流程实例")
    public Result<Object> cancellation(@ApiParam("流程实例id") @RequestParam("procInstId") String procInstId){

        iActivitiTaskService.handleCancellation(procInstId);
        ActReModelFormData actReModelFormData = iActReModelFormDataService.getOne(new QueryWrapper<ActReModelFormData>().eq("process_instance_id", procInstId));
        if(actReModelFormData.getTableName() != null){
        	this.fieldService.editFormBpmStatus(actReModelFormData.getDataId(), actReModelFormData.getTableName(), ActivitiConstant.HANDLE_STATUS_YZF+"");
        }

        return Result.OK();
    }

    @GetMapping("/revocation")
    @ApiOperation(value = "撤销流程实例", notes = "撤销流程实例")
    public Result<Object> revocation(@ApiParam(value = "procInstId" , name="流程实例id") @RequestParam String procInstId){

        iActivitiTaskService.revocation(procInstId);
        ActReModelFormData actReModelFormData = iActReModelFormDataService.getOne(new QueryWrapper<ActReModelFormData>().eq("process_instance_id", procInstId));
        if(actReModelFormData.getTableName() != null){
        	this.fieldService.editFormBpmStatus(actReModelFormData.getDataId(), actReModelFormData.getTableName(), ActivitiConstant.HANDLE_STATUS_YCX+"");
        }
        
        return Result.OK();
    }
}
